package com.alks.function.service.impl.biocontrol.deptwork;

import com.alibaba.excel.util.StringUtils;
import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.service.RedisService;
import com.alks.common.utils.DateUtils;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.entity.data.entity.*;
import com.alks.entity.data.page.PageParam;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.biocontrol.deptwork.ScheduleHeadDto;
import com.alks.function.data.dto.biocontrol.deptwork.ScheduleLotDto;
import com.alks.function.data.request.biocontrol.deptwork.SchHeadMovRequest;
import com.alks.function.data.request.biocontrol.deptwork.ScheduleLotRequest;
import com.alks.function.data.vo.biocontrol.deptwork.ScheduleHeadExcelVo;
import com.alks.function.mapper.biocontrol.deptwork.*;
import com.alks.function.mapper.chengKong.PcLotHeadMapper;
import com.alks.function.service.biocontrol.deptwork.IPsScehduleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import static com.alks.entity.data.enums.RedisKeyEnum.SCHEDULE_UP;
import static com.alks.entity.data.enums.ResultCodeEnum.INPUT_ERROR;

@Service
@Slf4j
@RequiredArgsConstructor
public class PsScehduleServiceImpl extends ServiceImpl<BC_DW_PsScheduleLotMapper, PsScheduleLot> implements IPsScehduleService {
    private final BC_DW_PsLtCommonMapper ltCommonMapper;
    private final BC_DW_PsLineCustomMapper customMapper;
    private final BC_DW_PsHolidayMapper holidayMapper;
    private final BC_DW_PsDayPercentMapper dayPercentMapper;
    private final BC_DW_PsStyleCurveMapper curveMapper;
    private final BC_DW_PsLineMapper lineMapper;
    private final BC_DW_PsStyleIeMapper ieMapper;
    private final BC_DW_PsScheduleLotMapper scheduleLotMapper;
    private final BC_DW_PsScheduleHeadMapper scheduleHeadMapper;
    private final PcLotHeadMapper lotHeadMapper;
    private final BC_DW_PcLotLtTimeMapper ltTimeMapper;
    private final RedisService redisService;

    @Override
    public ResponseInfo getLineQuery() {
        /*获取数据*/
        LambdaQueryWrapper<PsLine> wrapper = new LambdaQueryWrapper<PsLine>()
                .eq(PsLine::getCompanyId, UserIdThread.get().getCompanyId());
        List<PsLine> dtos = lineMapper.selectList(wrapper);
        return ResponseInfo.ok(dtos);
    }

    @Override
    @AutoPageAop
    public ResponseInfo getHolidayQuery(PageParam request) {
        /*获取数据*/
        LambdaQueryWrapper<PsHoliday> wrapper = new LambdaQueryWrapper<PsHoliday>()
                .ge(PsHoliday::getHolidayDate, LocalDateTime.now())
                .eq(PsHoliday::getCompanyId, UserIdThread.get().getCompanyId());
        List<PsHoliday> dtos = holidayMapper.selectList(wrapper);
        Page<PsHoliday> page = (Page<PsHoliday>) dtos;
        /*封装返回*/
        Map<String, Object> map = new HashMap<>();
        map.put("dtos", dtos);
        map.put("total", page.getTotal());
        return ResponseInfo.ok(map);
    }

    @Override
    @AutoPageAop
    public ResponseInfo getIEQuery(PageParam request, String style) {
        /*获取数据*/
        LambdaQueryWrapper<PsStyleIe> wrapper = new LambdaQueryWrapper<PsStyleIe>()
                .eq(style != null && !style.isEmpty(), PsStyleIe::getStyle, style)
                .eq(PsStyleIe::getCompanyId, UserIdThread.get().getCompanyId());
        List<PsStyleIe> dtos = ieMapper.selectList(wrapper);
        Page<PsStyleIe> page = (Page<PsStyleIe>) dtos;
        /*封装返回*/
        Map<String, Object> map = new HashMap<>();
        map.put("dtos", dtos);
        map.put("total", page.getTotal());
        return ResponseInfo.ok(map);
    }

    @Override
    @AutoPageAop
    public ResponseInfo getCustomQuery(@RequestBody PageParam request) {
        /*获取数据*/
        LambdaQueryWrapper<PsLineCustom> wrapper = new LambdaQueryWrapper<PsLineCustom>()
                .eq(PsLineCustom::getCompanyId, UserIdThread.get().getCompanyId());
        List<PsLineCustom> dtos = customMapper.selectList(wrapper);
        Page<PsLineCustom> page = (Page<PsLineCustom>) dtos;
        /*封装返回*/
        Map<String, Object> map = new HashMap<>();
        map.put("dtos", dtos);
        map.put("total", page.getTotal());
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo getCurveQuery() {
        /*获取数据*/
        LambdaQueryWrapper<PsStyleCurve> wrapper = new LambdaQueryWrapper<PsStyleCurve>()
                .eq(PsStyleCurve::getCompanyId, UserIdThread.get().getCompanyId());
        List<PsStyleCurve> dtos = curveMapper.selectList(wrapper);
        return ResponseInfo.ok(dtos);
    }

    @Override
    public ResponseInfo getLtCommonQuery() {
        /*获取数据*/
        LambdaQueryWrapper<PsLtCommon> wrapper = new LambdaQueryWrapper<PsLtCommon>()
                .eq(PsLtCommon::getCompanyId, UserIdThread.get().getCompanyId())
                .last("LIMIT 1");
        PsLtCommon dtos = ltCommonMapper.selectOne(wrapper);
        return ResponseInfo.ok(dtos);
    }

    @Override
    @AutoPageAop
    public ResponseInfo getDayPercentQuery(PageParam request, String line, LocalDateTime time) {
        /*获取数据*/
        LambdaQueryWrapper<PsDayPercent> wrapper = new LambdaQueryWrapper<PsDayPercent>()
                .eq(StringUtils.isNotBlank(line) && !line.isEmpty(), PsDayPercent::getLine, line)
                .eq(time != null, PsDayPercent::getDdate, time)
                .eq(PsDayPercent::getCompanyId, UserIdThread.get().getCompanyId())
                .orderByDesc(PsDayPercent::getDdate);
        List<PsDayPercent> dtos = dayPercentMapper.selectList(wrapper);
        Page<PsDayPercent> page = (Page<PsDayPercent>) dtos;
        /*封装返回*/
        Map<String, Object> map = new HashMap<>(2);
        map.put("dtos", dtos);
        map.put("total", page.getTotal());
        return ResponseInfo.ok(map);
    }


    @Override
    public ResponseInfo lineAdd(PsLine request) {
        if (StringUtils.isBlank(request.getWorkshop()) || StringUtils.isBlank(request.getLine())) {
            return ResponseInfo.error("车间代码和生产线名称不能为空", INPUT_ERROR.getCode());
        }
        /*判断车间代码是否重复*/
        LambdaQueryWrapper<PsLine> wrapper = new LambdaQueryWrapper<PsLine>()
                .eq(PsLine::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsLine::getWorkshop, request.getWorkshop())
                .or().eq(PsLine::getLine, request.getLine());
        Integer count = lineMapper.selectCount(wrapper);
        if (count > 0) {
            return ResponseInfo.error("车间代码和生产线名称不能重复", INPUT_ERROR.getCode());
        }
        /*补全数据*/
        request.setCompanyId(UserIdThread.get().getCompanyId());
        request.setSysDate(LocalDateTime.now());
        request.setUserId(UserIdThread.get().getLoginName());
        /*写入数据*/
        lineMapper.insert(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo holidayAdd(PsHoliday request) {
        /*判断型体是否重复*/
        LambdaQueryWrapper<PsHoliday> wrapper = new LambdaQueryWrapper<PsHoliday>()
                .eq(PsHoliday::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsHoliday::getHolidayDate, request.getHolidayDate());
        Integer count = holidayMapper.selectCount(wrapper);
        if (count > 0) {
            return ResponseInfo.error("日期不能重复", INPUT_ERROR.getCode());
        }
        /*补全数据*/
        request.setCompanyId(UserIdThread.get().getCompanyId());
        request.setSysDate(LocalDateTime.now());
        request.setUserId(UserIdThread.get().getLoginName());
        /*写入数据*/
        holidayMapper.insert(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo iEAdd(PsStyleIe request) {
        /*判断型体是否重复*/
        LambdaQueryWrapper<PsStyleIe> wrapper = new LambdaQueryWrapper<PsStyleIe>()
                .eq(PsStyleIe::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsStyleIe::getStyle, request.getStyle());
        Integer count = ieMapper.selectCount(wrapper);
        if (count > 0) {
            return ResponseInfo.error("型体不能重复", INPUT_ERROR.getCode());
        }
        /*补全数据*/
        request.setCompanyId(UserIdThread.get().getCompanyId());
        request.setSysDate(LocalDateTime.now());
        request.setUserId(UserIdThread.get().getLoginName());
        /*写入数据*/
        ieMapper.insert(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo customAdd(PsLineCustom request) {
        /*补全数据*/
        request.setCompanyId(UserIdThread.get().getCompanyId());
        /*写入数据*/
        customMapper.insert(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo curveAdd(PsStyleCurve request) {
        /*补全数据*/
        request.setCompanyId(UserIdThread.get().getCompanyId());
        request.setSysDate(LocalDateTime.now());
        request.setUserId(UserIdThread.get().getLoginName());
        /*写入数据*/
        curveMapper.insert(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo dayPercentAdd(PsDayPercent request) {
        /*判断是否重复*/
        if (percRepCheck(request)){
            return ResponseInfo.error("该产线已有此日期排产数据", INPUT_ERROR.getCode());
        }
        /*补全数据*/
        request.setCompanyId(UserIdThread.get().getCompanyId());
        request.setProcessType("LAST");
        /*写入数据*/
        dayPercentMapper.insert(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo lineUpdate(PsLine request, String workshopOld) {
        /*判断新车间代码是否重复*/
        LambdaQueryWrapper<PsLine> wrapperQ = new LambdaQueryWrapper<PsLine>()
                .eq(PsLine::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsLine::getLine, request.getLine());
        Integer count = lineMapper.selectCount(wrapperQ);
        if (count > 0) {
            return ResponseInfo.error("车间代码不能重复", INPUT_ERROR.getCode());
        }
        /*更新数据*/
        LambdaQueryWrapper<PsLine> wrapperU = new LambdaQueryWrapper<PsLine>()
                .eq(PsLine::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsLine::getWorkshop, workshopOld);
        lineMapper.update(request, wrapperU);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo holidayUpdate(PsHoliday request, LocalDateTime holidayDateOld) {
        /*判断新车间代码是否重复*/
        LambdaQueryWrapper<PsHoliday> wrapperQ = new LambdaQueryWrapper<PsHoliday>()
                .eq(PsHoliday::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsHoliday::getHolidayDate, request.getHolidayDate());
        Integer count = holidayMapper.selectCount(wrapperQ);
        if (count > 0) {
            return ResponseInfo.error("日期不能重复", INPUT_ERROR.getCode());
        }
        /*更新数据*/
        LambdaQueryWrapper<PsHoliday> wrapperU = new LambdaQueryWrapper<PsHoliday>()
                .eq(PsHoliday::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsHoliday::getHolidayDate, holidayDateOld);
        holidayMapper.update(request, wrapperU);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo iEUpdate(PsStyleIe request, String styleOld) {
        /*判断型体是否重复*/
        LambdaQueryWrapper<PsStyleIe> wrapper = new LambdaQueryWrapper<PsStyleIe>()
                .eq(PsStyleIe::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsStyleIe::getStyle, request.getStyle());
        Integer count = ieMapper.selectCount(wrapper);
        if (count > 0) {
            return ResponseInfo.error("型体不能重复", INPUT_ERROR.getCode());
        }
        /*更新数据*/
        LambdaQueryWrapper<PsStyleIe> wrapperU = new LambdaQueryWrapper<PsStyleIe>()
                .eq(PsStyleIe::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsStyleIe::getStyle, styleOld);
        ieMapper.update(request, wrapperU);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo customUpdate(PsLineCustom request) {
        /*更新数据*/
        customMapper.updateById(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo curveUpdate(PsStyleCurve request) {
        /*更新数据*/
        curveMapper.updateById(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo ltCommonUpdate(PsLtCommon request) {
        /*更新数据*/
        ltCommonMapper.updateById(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo dayPercentUpdate(PsDayPercent request) {
        /*检验线别是否存在*/
        String companyId = UserIdThread.get().getCompanyId();
        LambdaQueryWrapper<PsLine> wrapper = new LambdaQueryWrapper<PsLine>()
                .eq(PsLine::getCompanyId, companyId)
                .eq(PsLine::getLine, request.getLine());
        if (lineMapper.selectCount(wrapper)==0) {
            return ResponseInfo.error("线别不存在", INPUT_ERROR.getCode());
        }
        /*判断是否重复*/
        if (percRepCheck(request)){
            return ResponseInfo.error("该产线已有此日期排产数据", INPUT_ERROR.getCode());
        }
        /*更新数据*/
        dayPercentMapper.updateById(request);
        return ResponseInfo.ok();
    }

    /**
     * 判断排产数据是否重复
     */
    private boolean percRepCheck(PsDayPercent request) {
        LambdaQueryWrapper<PsDayPercent> wrapper = new LambdaQueryWrapper<PsDayPercent>()
                .eq(PsDayPercent::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsDayPercent::getLine, request.getLine())
                .eq(PsDayPercent::getDdate, request.getDdate());
        if (dayPercentMapper.selectCount(wrapper) > 0) {
            return true;
        }
        return false;
    }

    @Override
    public ResponseInfo lineDelete(String wrokShopOld) {
        /*删除对应数据*/
        LambdaQueryWrapper<PsLine> wrapper = new LambdaQueryWrapper<PsLine>()
                .eq(PsLine::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsLine::getWorkshop, wrokShopOld);
        lineMapper.delete(wrapper);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo holidayDelete(LocalDateTime holidayDateOld) {
        /*删除对应数据*/
        LambdaQueryWrapper<PsHoliday> wrapper = new LambdaQueryWrapper<PsHoliday>()
                .eq(PsHoliday::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsHoliday::getHolidayDate, holidayDateOld);
        holidayMapper.delete(wrapper);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo iEDelete(String styleOld) {
        /*删除对应数据*/
        LambdaQueryWrapper<PsStyleIe> wrapper = new LambdaQueryWrapper<PsStyleIe>()
                .eq(PsStyleIe::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsStyleIe::getStyle, styleOld);
        ieMapper.delete(wrapper);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo customDelete(Integer id) {
        /*删除对应数据*/
        customMapper.deleteById(id);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo curveDelete(Integer id) {
        /*删除对应数据*/
        curveMapper.deleteById(id);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo dayPercentDelete(Integer id) {
        /*删除对应数据*/
        dayPercentMapper.deleteById(id);
        return ResponseInfo.ok();
    }

    @Override
    @Transactional
    public ResponseInfo monthHolidayAdd() {
        /*获取下月所有周日的日期*/
        LocalDate today = LocalDate.now();
        LocalDate firstDayOfNextMonth = today.plusMonths(1).withDayOfMonth(1);
        LocalDate nextSunday = firstDayOfNextMonth.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        List<LocalDate> nextSundays = new ArrayList<>();
        while (nextSunday.getMonthValue() == firstDayOfNextMonth.getMonthValue()) {
            nextSundays.add(nextSunday);
            nextSunday = nextSunday.plusWeeks(1);
        }
        /*写入数据*/
        for (LocalDate sunday : nextSundays) {
            PsHoliday psHoliday = new PsHoliday();
            psHoliday.setHolidayDate(sunday.atStartOfDay());
            psHoliday.setUserId(UserIdThread.get().getLoginName());
            psHoliday.setCompanyId(UserIdThread.get().getCompanyId());
            psHoliday.setSysDate(LocalDateTime.now());
            holidayMapper.insert(psHoliday);
        }
        return ResponseInfo.ok();
    }

    @Override
    @Transactional
    public ResponseInfo monthPercentAdd(String date) {
        /*获取对应全部日期*/
        List<LocalDate> dates = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDate start = LocalDate.parse(date + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
        LocalDate end = start.plusMonths(1).minusDays(1);
        while (!start.isAfter(end)) {
            dates.add(start);
            start = start.plusDays(1);
        }
        /*遍历*/
        LambdaQueryWrapper<PsLine> wrapper = new LambdaQueryWrapper<PsLine>()
                .eq(PsLine::getCompanyId, UserIdThread.get().getCompanyId());
        List<String> lines = lineMapper.selectList(wrapper).stream().map(PsLine::getLine).collect(Collectors.toList());
        /*删除原本数据*/
        LambdaQueryWrapper<PsDayPercent> wrapperDelete = new LambdaQueryWrapper<PsDayPercent>()
                .ge(PsDayPercent::getDdate, start)
                .le(PsDayPercent::getDdate, end);
        dayPercentMapper.delete(wrapperDelete);
        /*写入数据*/
        for (String line : lines) {
            for (LocalDate localDate : dates) {
                PsDayPercent percent = new PsDayPercent();
                percent.setCompanyId(UserIdThread.get().getCompanyId());
                percent.setProcessType("LAST");
                percent.setLine(line);
                percent.setDdate(localDate.atStartOfDay());
                percent.setPercent(new BigDecimal(100));
                dayPercentMapper.insert(percent);
            }
        }
        return ResponseInfo.ok();
    }

    @Override
    @Transactional
    public ResponseInfo scheduleLotUp() {
        /*获取REDIS记录里的起始时间*/
        DateTimeFormatter formate = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String timeI = redisService.get(SCHEDULE_UP.getKey());
        /*如果起始时间为空则初始化赋值*/
        if (timeI == null || timeI.isEmpty()) {
            timeI = lambdaQuery()
                    .select(PsScheduleLot::getSysDate)
                    .eq(PsScheduleLot::getCompanyId, UserIdThread.get().getCompanyId())
                    .orderByDesc(PsScheduleLot::getSysDate)
                    .last("LIMIT 1").one().getSysDate()
                    .format(formate);
        }
        LocalDateTime timeUp = LocalDateTime.parse(timeI, formate);
        /*找出时间段之后的数据写入*/
        LambdaQueryWrapper<PcLotHead> wrapper = new LambdaQueryWrapper<PcLotHead>()
                .eq(PcLotHead::getCompanyId, UserIdThread.get().getCompanyId())
                .ge(PcLotHead::getSysDate, timeUp);
        List<PcLotHead> lotHeads = lotHeadMapper.selectList(wrapper);
        /*如果有数据则插入*/
        if (lotHeads != null && !lotHeads.isEmpty()) {
            List<PsScheduleLot> lots = BeanUtil.copyList(lotHeads, PsScheduleLot.class);
            for (PsScheduleLot lot : lots) {
                lot.setSysDate(LocalDateTime.now());
                lot.setUserId(UserIdThread.get().getCompanyId());
                lot.setSchFlag("N");
                scheduleLotMapper.insert(lot);
            }
        }
        /*更新所有订单数量*/
        scheduleLotMapper.scheduleLotUp();
        scheduleLotMapper.scheduleLotUp2();
        /*更新最后一次更新的时间*/
        String timeO = LocalDateTime.now().format(formate);
        redisService.set(SCHEDULE_UP.getKey(), timeO);
        return ResponseInfo.ok("更新成功");
    }

    @Override
    @AutoPageAop
    public ResponseInfo getScheduleLotQuery(ScheduleLotRequest request) {
        /*获取数据*/
        String companyId = UserIdThread.get().getCompanyId();
        List<ScheduleLotDto> dtos = scheduleLotMapper.getScheduleLotQuery(request, companyId);
        Page<ScheduleLotDto> page = (Page<ScheduleLotDto>) dtos;
        BigDecimal unInQtySum = dtos.stream()
                .map(ScheduleLotDto::getUnSchQty)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        /*封装数据*/
        Map<String, Object> map = new HashMap<>();
        map.put("dtos", dtos);
        map.put("total", page.getTotal());
        map.put("unInQtySum", unInQtySum);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo scheduleLotTF(String lotNo, String schFlag) {
        /*更新数据*/
        lambdaUpdate()
                .eq(PsScheduleLot::getCompanyId, UserIdThread.get().getCompanyId())
                .set(PsScheduleLot::getSchFlag, schFlag);
        return ResponseInfo.ok("成功");
    }

    @Override
    public ResponseInfo indexMove(SchHeadMovRequest request) {
        /*获取影响范围*/
        BigDecimal max = Collections.max(request.getSeqNo());
        BigDecimal min = Collections.min(request.getSeqNo());
        max = max.compareTo(request.getTargetSeqNo()) > 0 ? max : request.getTargetSeqNo();
        min = min.compareTo(request.getTargetSeqNo()) < 0 ? min : request.getTargetSeqNo();
        /*获取数据库中最大值*/
        BigDecimal dataMax = scheduleHeadMapper.indexMoveQuery(request, UserIdThread.get().getCompanyId());
        /*数据补正*/
        BigDecimal target = request.getTargetSeqNo().add(BigDecimal.valueOf(request.getSeqNo().size())).compareTo(max) > 0 ? max.subtract(BigDecimal.valueOf(request.getSeqNo().size())) : request.getTargetSeqNo();
        //超出上限的情况
        target = request.getTargetSeqNo().compareTo(BigDecimal.ONE) < 0 ? BigDecimal.ONE : request.getTargetSeqNo();           //小于1的情况
        /*获取范围内数据*/
        LambdaQueryWrapper<PsScheduleHead> wrapper2 = new LambdaQueryWrapper<PsScheduleHead>()
                .in(PsScheduleHead::getSeqNo, request.getSeqNo())
                .ge(PsScheduleHead::getLine, min)
                .le(PsScheduleHead::getLine, max)
                .eq(PsScheduleHead::getLine, request.getLine())
                .eq(PsScheduleHead::getCompanyId, UserIdThread.get().getCompanyId());
        List<PsScheduleHead> heads = scheduleHeadMapper.selectList(wrapper2);
        /*更新序号*/
        Set<BigDecimal> seqNos = new HashSet<>(request.getSeqNo());
        /*提取出待移序数据*/
        BigDecimal finalTarget = target;
        long count = seqNos.stream().filter(seqNo -> seqNo.compareTo(finalTarget) < 0).count();
        List<PsScheduleHead> heads1 = heads.stream().filter(a -> seqNos.contains(a.getSeqNo()) && (a.getSeqNo().compareTo(finalTarget) >= count))
                .sorted(Comparator.comparing(PsScheduleHead::getSeqNo)).collect(Collectors.toList());
        List<PsScheduleHead> heads2 = heads.stream().filter(a -> seqNos.contains(a.getSeqNo()) && a.getSeqNo().compareTo(finalTarget) < count)
                .sorted(Comparator.comparing(PsScheduleHead::getSeqNo)).collect(Collectors.toList());
        List<PsScheduleHead> heads3 = heads.stream().filter(a -> !seqNos.contains(a.getSeqNo()))
                .sorted(Comparator.comparing(PsScheduleHead::getSeqNo)).collect(Collectors.toList());
        /*保持顺序进行数据整合*/
        ArrayList<PsScheduleHead> headsEnd = new ArrayList<>(heads3);
        headsEnd.addAll(heads2);
        headsEnd.addAll(heads1);
        BigDecimal tag = min;
        /*循环分发序号*/
        for (PsScheduleHead head : headsEnd) {
            head.setSeqNo(tag);
            tag = tag.add(BigDecimal.ONE);
        }
        /*修改对应数据*/
        scheduleHeadMapper.indexMove(headsEnd);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo lineMove(SchHeadMovRequest request) {
        /*更新数据*/
        LambdaUpdateWrapper<PsScheduleHead> wrapperU = new LambdaUpdateWrapper<PsScheduleHead>()
                .eq(PsScheduleHead::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsScheduleHead::getLine, request.getLine())
                .in(PsScheduleHead::getSeqNo, request.getSeqNo())
                .set(PsScheduleHead::getLine, request.getTargetLine());
        scheduleHeadMapper.update(null, wrapperU);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo updateScheduleHead() {
        LocalDate date = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String format = date.format(formatter);
        //查询进度表中是否含有当天的数据 如果有将生产天数以及完成日期客户交期重置
        Integer count = scheduleHeadMapper.getCurrentList(format);
        if (count <= 0) {
            scheduleHeadMapper.insertIntoPcSch(format);
        } else {
            scheduleHeadMapper.deleteIntoPcSch(format, UserIdThread.get().getCompanyId());
            scheduleHeadMapper.insertIntoPcSch(format);
        }
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo getScheduleHeadQuery(String line, String lotNo, String style) {
        /*获取基础数据*/
        LambdaQueryWrapper<PsScheduleHead> wrapper = new LambdaQueryWrapper<PsScheduleHead>()
                .eq(PsScheduleHead::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsScheduleHead::getLine, line)
                .eq(lotNo != null && !lotNo.isEmpty(), PsScheduleHead::getLotNo, lotNo)
                .eq(style != null && !style.isEmpty(), PsScheduleHead::getStyle, style)
                .eq(PsScheduleHead::getScheduleNo, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        List<PsScheduleHead> heads = scheduleHeadMapper.selectList(wrapper);
        /*获取求和数据*/
        List<ScheduleHeadDto> dtos = BeanUtil.copyList(heads, ScheduleHeadDto.class);
        if (heads != null && !heads.isEmpty()) {
            List<String> lotNos = heads.stream().map(PsScheduleHead::getLotNo).collect(Collectors.toList());
            LambdaQueryWrapper<PcLotHead> wrapper1 = new LambdaQueryWrapper<PcLotHead>()
                    .eq(PcLotHead::getCompanyId, UserIdThread.get().getCompanyId())
                    .in(PcLotHead::getLotNo, lotNos);
            /*获取欠数*/
            Map<String, Float> sumMap = lotHeadMapper.selectList(wrapper1)
                    .stream().collect(Collectors.toMap(PcLotHead::getLotNo,
                            a -> (a.getOrderQty() == null ? 0 : a.getOrderQty()) + (a.getSurplusQty() == null ? 0 : a.getSurplusQty())));
            for (ScheduleHeadDto dto : dtos) {
                dto.setShortSum(sumMap.get(dto.getLotNo()));
            }
        }
        /*提取数据*/
        BigDecimal scheduleSum = dtos.stream()
                .map(dto -> dto.getScheduleQty() != null ? dto.getScheduleQty() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal prodDaysSum = dtos.stream()
                .map(dto -> dto.getProdDays() != null ? dto.getProdDays() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO,BigDecimal::add);
        Map<String, Object> map = new HashMap<>();
        map.put("dtos", dtos);
        map.put("prodDaysSum", prodDaysSum);
        map.put("scheduleSum", scheduleSum);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo indexUpDown(SchHeadMovRequest request) {
        /*检验数据合法性*/
        Collections.sort(request.getSeqNo());
        BigDecimal dataMax = scheduleHeadMapper.indexMoveQuery(request, UserIdThread.get().getCompanyId());
        if ((request.getType().equals(-1) && request.getSeqNo().get(0).compareTo(BigDecimal.ONE) <= 0) ||
                (request.getType().equals(1) && request.getSeqNo().get(request.getSeqNo().size() - 1).equals(dataMax))) {
            return ResponseInfo.error("序号已经移到底了，不能继续移动", INPUT_ERROR.getCode());
        }
        /*更新数据*/
        scheduleHeadMapper.indexUpDown(request);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo scheduleHeadUp(String lotNo, String stdQty) {
        /*更新进度安排资料*/
        scheduleHeadMapper.scheduleHeadUp(lotNo, stdQty, UserIdThread.get().getCompanyId());
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo cptScheduleHead(LocalDate time) {
        /*查询数据*/
        LambdaQueryWrapper<PsScheduleHead> wrapper = new LambdaQueryWrapper<PsScheduleHead>()
                .eq(PsScheduleHead::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsScheduleHead::getScheduleNo, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")))
                .orderByAsc(PsScheduleHead::getLine, PsScheduleHead::getSeqNo);
        List<PsScheduleHead> heads = scheduleHeadMapper.selectList(wrapper);
        /*循环计算和补充数据*/
        BigDecimal upDay = BigDecimal.ZERO;
        LocalDate endDate = time;
        for (PsScheduleHead head : heads) {
            BigDecimal orderQty = head.getOrderQty() == null ? BigDecimal.ZERO : head.getOrderQty();
            BigDecimal stdQty = head.getStdQty() == null ? BigDecimal.ZERO : head.getStdQty();
            BigDecimal prodDay = orderQty.divide(stdQty);   //订单/产能=日期
            head.setProdDays(prodDay);
            head.setBeginDate(time.atStartOfDay());
            /*计算结束日期*/
            upDay.add(prodDay);
            endDate = endDate.plusDays(upDay.intValue());
            head.setEndDate(endDate.atStartOfDay());
            upDay = upDay.subtract(new BigDecimal(upDay.intValue())); // 保留小数部分
        }
        return ResponseInfo.ok();
    }

    @Override
    @Transactional
    public ResponseInfo scheduleHeadAdd(List<String> lotNos, String line) {
        /*获取要写入的数据*/
        List<PsScheduleLot> lots = lambdaQuery().in(PsScheduleLot::getLotNo, lotNos)
                .eq(PsScheduleLot::getCompanyId, UserIdThread.get().getCompanyId())
                .list();
        Map<String, BigDecimal> schQty = lots.stream().collect(Collectors.toMap(
                PsScheduleLot::getLotNo, a -> a.getOrderQty().subtract(a.getSchQty().add(a.getInQty()))));
        /*获取人均日产能*/
        LambdaQueryWrapper<PsLine> lineWrapper = new LambdaQueryWrapper<PsLine>()
                .select(PsLine::getPersons)
                .eq(PsLine::getCompanyId, UserIdThread.get().getCompanyId())
                .eq(PsLine::getLine, line)
                .last("LIMIT 1");
        BigDecimal persons = lineMapper.selectOne(lineWrapper).getPersons();
        LambdaQueryWrapper<PcLotLtTime> ltTimeWrappeer = new LambdaQueryWrapper<PcLotLtTime>()
                .in(PcLotLtTime::getLotNo, lotNos);
        Map<String, BigDecimal> stdQty = ltTimeMapper.selectList(ltTimeWrappeer).stream()       //产能=人均日产能*人数
                .collect(Collectors.toMap(PcLotLtTime::getLotNo, a -> a.getLastPpd().multiply(persons)));
        /*整理补充数据*/
        List<PsScheduleHead> heads = BeanUtil.copyList(lots, PsScheduleHead.class);
        for (PsScheduleHead head : heads) {
            head.setStdQty(stdQty.get(head.getLotNo()));
            head.setLine(line);
            head.setScheduleNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
            head.setScheduleQty(schQty.get(head.getLotNo()));
            /*写入数据*/
            scheduleHeadMapper.insert(head);
        }
        /*更新指令表中的状态码*/
        for (PsScheduleLot lot : lots) {
            LambdaQueryWrapper<PsScheduleLot> wrapper = new LambdaQueryWrapper<PsScheduleLot>()
                    .eq(PsScheduleLot::getLotNo, lot.getLotNo());
            lot.setSchQty(schQty.get(lot.getLotNo()));
            scheduleLotMapper.update(lot, wrapper);
        }
        return ResponseInfo.ok();
    }

    @Override
    @Transactional
    public ResponseInfo scheduleHeadDelete(List<String> lotNo) {
        /*查询原本数据*/
        String companyId = UserIdThread.get().getCompanyId();
        LambdaQueryWrapper<PsScheduleHead> wrapper = new LambdaQueryWrapper<PsScheduleHead>()
                .eq(PsScheduleHead::getCompanyId, companyId)
                .in(PsScheduleHead::getLotNo, lotNo);
        Map<String, BigDecimal> scheduleQty = scheduleHeadMapper.selectList(wrapper)
                .stream().collect(Collectors.toMap(PsScheduleHead::getLotNo, PsScheduleHead::getScheduleQty));
        /*删除基础表中数据*/
        scheduleHeadMapper.delete(wrapper);
        /*回滚指令表数据*/
        scheduleLotMapper.scheduleHeadDelete(scheduleQty, companyId);
        return ResponseInfo.ok();
    }

    @Override
    public List<ScheduleHeadExcelVo> scheduleHeadExpord() {
        /*获取数据*/
        List<ScheduleHeadExcelVo> vos=scheduleHeadMapper.scheduleHeadExpord(UserIdThread.get().getCompanyId());
        /*对数据进行分组拆分处理*/
        Map<String, List<ScheduleHeadExcelVo>> groupMap = vos.stream()
                .collect(Collectors.groupingBy(ScheduleHeadExcelVo::getLine));
        List<List<ScheduleHeadExcelVo>> groupList = new ArrayList<>(groupMap.values());
        /*插入合计数据*/
        for (List<ScheduleHeadExcelVo> list : groupList) {
            int seqNo = 0;
            Float orderQty = 0f;
            BigDecimal scheduleQty = BigDecimal.ZERO;
            BigDecimal short1 = BigDecimal.ZERO;
            String line = null;
            for (ScheduleHeadExcelVo vo : list) {
                /*重写seqNo*/
                vo.setSeqNo(++seqNo);
                orderQty +=vo.getOrderQty();
                scheduleQty = scheduleQty.add(vo.getScheduleQty());
                short1 = short1.add(vo.getShort1());
                line = vo.getLine();
            }
            ScheduleHeadExcelVo totalVo = new ScheduleHeadExcelVo();
            totalVo.setLine(line+"合计");
            totalVo.setOrderQty(orderQty);
            totalVo.setScheduleQty(scheduleQty);
            totalVo.setShort1(short1);
            list.add(totalVo);
        }
        /*拼接数据*/
        vos=new ArrayList<>(0);
        for (List<ScheduleHeadExcelVo> list : groupList) {
            vos.addAll(list);
        }
        return vos;
    }

    @Override
    @AutoPageAop
    public ResponseInfo getScheduleQuery(ScheduleLotRequest request) {
        /*获取数据*/
        List<ScheduleHeadDto> dtos = scheduleHeadMapper.getScheduleQuery(request, UserIdThread.get().getCompanyId());
        Page<ScheduleHeadDto> page = (Page<ScheduleHeadDto>) dtos;
        /*封装数据*/
        Map<String, Object> map = new HashMap<>();
        map.put("dtos", dtos);
        map.put("total", page.getTotal());
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo getStyleBack() {
        /*获取数据*/
        LambdaQueryWrapper<PsScheduleHead> wrapper=new LambdaQueryWrapper<PsScheduleHead>()
                .groupBy(PsScheduleHead::getStyle);
        /*提取型体*/
        List<String> style = scheduleHeadMapper.selectList(wrapper)
                .stream().map(PsScheduleHead::getStyle).collect(Collectors.toList());
        return ResponseInfo.ok(style);
    }

    @Override
    public void percentMonthAdd(String month) {
        String companyId = UserIdThread.get().getCompanyId();
        /*获取日期集合*/
        List<LocalDateTime> monthDayList = DateUtils.getDatesInMonth(month);
        /*月份处理*/
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");
        YearMonth yearMonth = YearMonth.parse(month, formatter);
        LocalDate firstDay = yearMonth.atDay(1);
        LocalDate lastDay = yearMonth.atEndOfMonth();
        /*获取节假日 和 周日*/
        LambdaQueryWrapper<PsHoliday> wrapper = new LambdaQueryWrapper<PsHoliday>()
                .select(PsHoliday::getHolidayDate)
                .eq(PsHoliday::getCompanyId, companyId)
                .ge(PsHoliday::getHolidayDate, firstDay)
                .le(PsHoliday::getHolidayDate, lastDay)
                .isNotNull(PsHoliday::getHolidayDate)
                .groupBy(PsHoliday::getHolidayDate);
        Set<LocalDateTime> holidays = holidayMapper.selectList(wrapper)
                .stream().filter(Objects::nonNull)
                .map(PsHoliday::getHolidayDate)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Set<LocalDateTime> weekends = getWeekends(firstDay, lastDay);
        holidays.addAll(weekends);
        /*拼装生产线和排产日期*/
        List<PsLine> lines = lineMapper.selectList(new LambdaQueryWrapper<PsLine>()
                .select(PsLine::getLine)
                .eq(PsLine::getCompanyId, companyId));
        List<PsDayPercent> psDayPercentList = new ArrayList<>();
        /*剔除已存在数据*/
        LambdaQueryWrapper<PsDayPercent> percentWrapper = new LambdaQueryWrapper<PsDayPercent>()
                .eq(PsDayPercent::getCompanyId, companyId)
                .ge(PsDayPercent::getDdate, firstDay)
                .le(PsDayPercent::getDdate, lastDay);
        List<PsDayPercent> psDaytList = dayPercentMapper.selectList(percentWrapper);
        Set<String> removeSet = psDaytList.stream()
                .map(a -> a.getLine() + "_" + a.getDdate())
                .collect(Collectors.toSet());
        for (PsLine line : lines) {
            for (LocalDateTime time : monthDayList) {
                if (removeSet.contains(line.getLine() + "_" + time)){
                    continue;
                }
                /*拼接待写入数据*/
                PsDayPercent psDayPercent = new PsDayPercent();
                psDayPercent.setLine(line.getLine());
                psDayPercent.setDdate(time);
                /*节假日排量为0*/
                BigDecimal percent = holidays.contains(time) ?
                        BigDecimal.ZERO :
                        BigDecimal.valueOf(100);
                psDayPercent.setPercent(percent);

                psDayPercent.setCompanyId(companyId);
                psDayPercent.setProcessType("LAST");
                psDayPercentList.add(psDayPercent);
            }
        }
        if (ArrayUtils.isEmpyt(psDayPercentList)){
            throw new ServiceErrorException("该月份已有排产数据");
        }
        dayPercentMapper.insertBatch(psDayPercentList);
    }

    private static Set<LocalDateTime> getWeekends(LocalDate startDate, LocalDate endDate) {
        Set<LocalDateTime> weekends = new HashSet<>();
        LocalDate date = startDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        while (!date.isAfter(endDate)) {
            weekends.add(date.atStartOfDay());
            date = date.plusWeeks(1);
        }
        return weekends;
    }

}
